/**
 * 深度取值
 * @param data 
 * @param subKey  
 * @param defaultVaue 默认值
 * @returns 
 */
export function DeepGet(data: Object, subKey: string, defaultVaue: any = '') {
  try {
    let value: Object = data;
    subKey.split('.').forEach((key: string) => {
      value = value[key as keyof typeof value]
    });
    return value;
  } catch {
    return defaultVaue;
  }
}
/**
 * 
 * @param obj 
 * @returns 
 */
export function TypeOf<T>(obj: T): string {
  const toString = Object.prototype.toString
  const map = (s: string): string => ({
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object',
  })[s] || ""
  return map(toString.call(obj));
}
/**
 * 
 * @param data 深度赋值
 * @returns 
 */
export function DeepClone(data: any) {
  const t = TypeOf(data)
  let o: any
  if (t === 'array') {
    o = []
  } else if (t === 'object') {
    o = {}
  } else {
    return data
  }
  if (t === 'array') {
    for (let i: number = 0; i < data.length; i++) {
      o.push(DeepClone(data[i]))
    }
  } else if (t === 'object') {
    for (let i in data) {
      o[i] = DeepClone(data[i])
    }
  }
  return o;
}
export function DeepAssign(date: Object) {
  let o = {};
  Object.values(date).forEach(i => Object.assign(o, i));
  return o;
}
/**
 * 防抖
 * @param fn 
 * @param wait 
 * @returns 
 */
export function debounce(fn: Function, wait: number = 500): Function {
  let timer: NodeJS.Timeout | null = null;
  return function (this: any) {
    if(timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, wait)
  }
};
/**
 * 节流
 * @param fn 
 * @param wait 延时 
 * @returns 
 */
export function thorttle(fn: Function, wait: number = 500) {
  let flag = true;
  let timer: NodeJS.Timeout | null = null;
  return function (this: any) {
    if (!flag) return;
    fn.apply(this, arguments);
    flag = false;
    timer = setTimeout(() => {
      flag = true;
    }, wait)
  }
};
/**
* 判断此对象是否是Object类型
* @param {Object} obj
*/
export function isObject<T>(obj: T): boolean {
  return Object.prototype.toString.call(obj) === '[object Object]';
};
/**
 * 判断此类型是否是Array类型
 * @param {Array} obj
 */
export function isArray<T>(obj: T): boolean {
  return Object.prototype.toString.call(obj) === '[object Array]';
};
/**
 * 判断两个对象是否相等
 * @param obj1 
 * @param obj2 
 * @returns 
 */
export function equalsObj(obj1: any, obj2: any, sortKey?: string): boolean {
  try {
    if (obj1 === obj2) return true;
    if (isObject(obj1) && isObject(obj2) && Object.keys(obj1).length === Object.keys(obj2).length) {
      for (const key in obj1) {
        if (!obj2.hasOwnProperty(key)) return false;
        if (!equalsObj(obj1[key], obj2[key])) return false;
      }
    } else if (isArray(obj1) && isArray(obj2) && obj1.length === obj2.length) {
      if (sortKey) {
        AscSort(obj1, sortKey);
        AscSort(obj2, sortKey);
      }
      for (let key in obj1) {
        if (!equalsObj(obj1[key], obj2[key])) return false;
      }
    }
    return false;
  } catch {
    return false;
  }
};
export function AscSort(obj: Object[], sortKey: string) {
  obj.sort((a: any, b: any) => DeepGet(a, sortKey) - DeepGet(b, sortKey))
}
export function DescSort(obj: Object[], sortKey: string) {
  obj.sort((a: any, b: any) => DeepGet(b, sortKey) - DeepGet(a, sortKey))
}